package com.lx.idgenerator.segement;

import com.lx.idgenerator.base.model.IDWrapper;
import com.lx.idgenerator.exception.BizException;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * @author lX
 * @version JDK 8
 * @className Segment (此处以class为例)
 * @date 2024/10/28
 * @description TODO
 */
public class Segment {
    /**
     * 最小ID
     */
    private long minId;
    /**
     * 当前ID
     */
    private volatile long curId;
    /**
     * 最大ID
     */
    private long maxId;
    /**
     * 当前ID偏移量
     */
    private static final long CUR_ID_OFFSET;

    private static final Unsafe UNSAFE;

    static {
        try {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            UNSAFE = (Unsafe) theUnsafe.get(null);
            //记录当前curId 的偏移量  CAS 原子操作
            CUR_ID_OFFSET = UNSAFE.objectFieldOffset(Segment.class.getDeclaredField("curId"));
        } catch (Exception e) {
            throw new BizException(e.getMessage(), e);
        }
    }

    public long getMinId() {
        return minId;
    }

    public void setMinId(long minId) {
        this.minId = minId;
    }

    public long getCurId() {
        return curId;
    }

    public void setCurId(long curId) {
        this.curId = curId;
    }

    public long getMaxId() {
        return maxId;
    }

    public void setMaxId(long maxId) {
        this.maxId = maxId;
    }


    public IDWrapper nextID(int size) {


        //返回 null 判断是否需要扩充
        IDWrapper idWrapper = null;

        for (; ; ) {
            //当前缓存中的值
            long curId = this.curId;

            //下次获取开始的值
            long nextId = curId + size;
            //如果当前值已经达到最大值,超过最大值就从外层方法进行扩容后再获取
            if (curId == maxId) {
                break;
            }
            //如果还有余号可以拿  把当前号更新为新的号
            if (maxId >= nextId && compareAndSwapCurId(curId, nextId)) {
                idWrapper = new IDWrapper();
                idWrapper.setCurId(curId);
                idWrapper.setMinId(curId);
                idWrapper.setMaxId(nextId);
                break;
            }

            //如果批量获取的时候,余号不够,那就返回给到最大值的位置
            long diff = maxId - curId;
            if (nextId > maxId && diff > 0 && compareAndSwapCurId(curId, maxId)) {
                idWrapper = new IDWrapper();
                idWrapper.setCurId(curId);
                idWrapper.setMinId(curId);
                idWrapper.setMaxId(maxId);
                break;
            }


        }

        return idWrapper;

    }

    private boolean compareAndSwapCurId(long curId, long nextId) {
        return UNSAFE.compareAndSwapLong(this, CUR_ID_OFFSET, curId, nextId);
    }

    /**
     * 获取分段ID使用率
     *
     * @return
     */
    public BigDecimal usedPercent() {
        BigDecimal percent;
        //如果maxId为0 说明没有填充过,直接进行更新
        if (maxId == 0) {
            percent = new BigDecimal(100);
        } else {
            percent = new BigDecimal(curId - minId).multiply(new BigDecimal(100)).divide(new BigDecimal(maxId - minId), 3, RoundingMode.UP);
        }
        return percent;
    }
}
